package concurrecy.lock2;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class JannaBlockingQueue<T> {
    // 存放数据
    private LinkedList<T> list = new LinkedList<>();
    // 阻塞队列的大小
    private int length;

    private Lock lock = new ReentrantLock();
    private Condition takeCondition = lock.newCondition();
    private Condition putCondition = lock.newCondition();

    public JannaBlockingQueue(int length) {
        this.length = length;
    }

    /**
     * 把数据放到队列中，如果队列已满，则阻塞
     * @param t
     */
    public void put(T t) {
        lock.lock();
        try {
            for(;;) {
                // 队列没满，直接放入
                if (list.size() < length) {
                    list.add(t);
                    takeCondition.signal();
                    return;
                } else {
                    putCondition.await();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 从队列中取数据，如果队列为空，则阻塞
     * @return
     */
    public T take() {
        lock.lock();
        try {
            for(;;) {
                // 队列不为空，直接返回头部元素
                if (list.size() > 0) {
                    T t = list.removeFirst();
                    putCondition.signal();
                    return t;
                } else
                    takeCondition.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }
}

public class MyBlockingQueue {
    public static void main(String[] args) throws InterruptedException {
        JannaBlockingQueue<String> blockingQueue = new JannaBlockingQueue<>(5);
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                String s = "s" + i;
                blockingQueue.put(s);
                System.out.println("put " + s);
            }
        }).start();

        for (int i = 0; i < 20; i++) {
            Thread.sleep(1000);
            System.out.println("take "+ blockingQueue.take());
        }
    }
}
